package com.onefish.toolkit.attack;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.nio.file.Files;
import java.nio.file.Paths;

/**
 * 枚举类型
 */
public enum SingletonEnum {
    INSTANCE;

    public void doSomething() {
        System.out.println("Singleton instance is doing something.");
    }

    public static void main(String[] args) throws Exception {
        try {
            SingletonEnum singleton1 = SingletonEnum.INSTANCE;
            //  Enum not exist reflect attack . because throw exception , for this reason .
            //  Exception in thread "main" java.lang.NoSuchMethodException: com.onefish.toolkit.attack.SingletonEnum.<init>()
            Constructor<SingletonEnum> constructor = SingletonEnum.class.getDeclaredConstructor();
            constructor.setAccessible(true);
            SingletonEnum singleton2 = constructor.newInstance();
            System.out.println("A singleton created by reflection is the same as another instance: : " + (singleton1 == singleton2));
            singleton1.doSomething();
            singleton2.doSomething();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        try {
            //  Enum not exist serialization attack , because these two instances are same .
            SingletonEnum singleton3 = SingletonEnum.INSTANCE;
            SingletonEnum singleton4;
            try (ObjectOutputStream out = new ObjectOutputStream(Files.newOutputStream(Paths.get("singleton.ser")))) {
                out.writeObject(singleton3);
            }
            try (ObjectInputStream in = new ObjectInputStream(Files.newInputStream(Paths.get("singleton.ser")))) {
                singleton4 = (SingletonEnum) in.readObject();
            }
            System.out.println("A singleton created by Serialization is the same as another instance:" + (singleton3 == singleton4));
            singleton3.doSomething();
            singleton4.doSomething();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
